#include "Uart_fifo.h"
#include <string.h>
#include "def.h"
#include "option.h"
#include "2440addr.h"  
  
#include "2440lib.h"

#include <fifo.h>

 
#define TX_INTTYPE 1	//0:Tx interrupt type is pulse, 1:Tx interrupt type is level
#define RX_INTTYPE 1	//0:Rx interrupt type is pulse, 1:Rx interrupt type is level

RAW_U8 TmpBuf[4096];
volatile RAW_U8 *pRead=TmpBuf;
volatile RAW_U8 *pWrite=TmpBuf;

void ISR_UART0_RxIntOrErr(void);
void __sub_Uart0_RxInt(void);
void __sub_Uart0_RxErrInt(void);


void Uart0Init_fifo(void)
{
	rULCON0=(0<<6)|(0<<3)|(0<<2)|(3);	// Normal,No parity,One stop bit, 8bit
	rUCON0 &= 0x400;	// For the PCLK <-> UCLK fuction
	rUCON0 |= (TX_INTTYPE<<9)|(RX_INTTYPE<<8)|(1<<7)|(1<<6)|(0<<5)|(0<<4)|(1<<2)|(1);
	//Clock,Tx:Def,Rx:Def,Rx timeout:o,Rx error int:o,Loop-back:x,Send break:x,Tx:int,Rx:int
	rUFCON0=(1<<6)|(2<<4)|(1<<2)|(1<<1)|(1);
	//Tx and Rx FIFO Trigger Level:16byte,Tx and Rx FIFO Reset,FIFO on

	// Clear Int Pending and Unmask 
	ClearPending(BIT_UART0);
	rINTMSK=~(BIT_UART0);
	rSUBSRCPND=(BIT_SUB_RXD0|BIT_SUB_TXD0|BIT_SUB_ERR0);
	rINTSUBMSK=~(BIT_SUB_RXD0|BIT_SUB_ERR0);

	register_irq(28, ISR_UART0_RxIntOrErr);
}

void ISR_UART0_RxIntOrErr(void)
{
	rINTSUBMSK|=(BIT_SUB_RXD0|BIT_SUB_TXD0|BIT_SUB_ERR0);
	if(rSUBSRCPND&BIT_SUB_RXD0) __sub_Uart0_RxInt();
	else __sub_Uart0_RxErrInt();
	ClearPending(BIT_UART0); 
	rSUBSRCPND=(BIT_SUB_RXD0|BIT_SUB_ERR0); // Clear Sub int pending	 
	rINTSUBMSK&=~(BIT_SUB_RXD0|BIT_SUB_ERR0);
}


#if (UART_RECEIVE_WAY > 0)

extern MEM_POOL MEM_FOR_UART;
extern RAW_QUEUE uart_queue;
void __sub_Uart0_RxInt(void)
{
	void *Buffer; 
	UART_MSG *msg; 
	unsigned char *pp;

	if( RAW_SUCCESS == raw_block_allocate(&MEM_FOR_UART,&Buffer) )
	{
		msg=(UART_MSG*)Buffer;
		msg->len = 0;
		msg->buf=(unsigned char*)msg+sizeof(UART_MSG);
		pp = (unsigned char*)msg+sizeof(UART_MSG);
		while(rUFSTAT0&0x7f)	 //During the Rx FIFO is not empty
		{
//				*msg->buf++ = RdURXH0(); 
			*pp++ = RdURXH0(); 
			msg->len++;
		}

		if(msg->len==0)
			raw_block_release(&MEM_FOR_UART,Buffer);
		else
		{
			raw_queue_end_post(&uart_queue, msg); 
		}	
	}
}
RAW_U32 uart_receive_t(RAW_U8 *buffer, RAW_U32 size, RAW_U32 timeout)
{
	RAW_U32 tmplen=0;
	void *msg_app1;
	UART_MSG *msg;
	RAW_U16 errstat;

	while((pWrite - pRead) < size)
	{
		errstat = raw_queue_receive (&uart_queue, timeout, &msg_app1);
		if(errstat == RAW_BLOCK_TIMEOUT)
			break;		
		if (errstat == RAW_SUCCESS) 
		{
			msg = (UART_MSG*)msg_app1;
			memcpy((void *)pWrite, msg->buf, msg->len);
			pWrite += msg->len;
			raw_block_release(&MEM_FOR_UART,msg_app1);
		}
	}

	if((pWrite - pRead) >= size)
	{
		for(;tmplen < size; tmplen++)
		{
			*buffer++ = *pRead++;
			if(pRead == pWrite)
			{
				pRead = TmpBuf;
				pWrite = TmpBuf;
			}
		}
	}
	return tmplen;
}

#else
extern RAW_SEMAPHORE s1;
extern struct raw_fifo fifo;
void __sub_Uart0_RxInt(void)
{
	RAW_U8 aa[256]={0};
	RAW_U8 *bb=aa;
	RAW_U8 len=0;

	while(rUFSTAT0&0x7f)	 //During the Rx FIFO is not empty
	{
		*bb = RdURXH0(); 
		bb++;
		len++;
	}
	fifo_in(&fifo, aa, len);
	raw_semaphore_put(&s1);
}

RAW_U32 uart_receive_t(RAW_U8 *buffer, RAW_U32 size, RAW_U32 timeout)
{
	RAW_U32 len=0;
	RAW_U32 tmplen=0;
	RAW_U16 errstat;

	while((pWrite - pRead) < size)
	{
		errstat = raw_semaphore_get(&s1, timeout);
		if(errstat == RAW_BLOCK_TIMEOUT)
			break;
		if(errstat == RAW_SUCCESS)
		{
			len = fifo_out_all(&fifo, (void *)pWrite);			
			pWrite += len;
		}
	}
	if((pWrite - pRead) >= size)
	{
		for(;tmplen < size; tmplen++)
		{
			*buffer++ = *pRead++;
			if(pRead == pWrite)
			{
				pRead = TmpBuf;
				pWrite = TmpBuf;
			}
		}
	}

	return tmplen;
}

#endif
void __sub_Uart0_RxErrInt(void)
{
	U32 iStatus;

	iStatus = rUERSTAT0;

	switch(iStatus)//to clear and check the status of register bits
	{
	case 1:
		Uart_Printf("Overrun error!\n");
	break;
	case 2:
		Uart_Printf("Parity error!\n");
	break;
	case 4:
		Uart_Printf("Frame error!\n");
	break;
	case 6:
		Uart_Printf("Parity, Frame error!\n");
	break;
	case 8:
		Uart_Printf("Breake detect\n");
	break;
	case 0xa:
		Uart_Printf("Parity error & Break detect!\n");
	break;
	case 0xc:
		Uart_Printf("Frame error & Breake detect\n");
	break;
	case 0xe:
		Uart_Printf("Parity, Frame error & Break detect!\n");
	break;
	default :
		Uart_Printf("Unknown error : 0x%x\n", iStatus);
	break;
	}

}



